/* * Sun Public License Notice * * The contents of this file are subject to the Sun Public License * Version 1.0 (the "License"). You may not use this file except in * compliance with the License. A copy of the License is available at * http://www.sun.com/ * * The Original Code is Forte for Java, Community Edition. The Initial * Developer of the Original Code is Sun Microsystems, Inc. Portions * Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved. */ package org.netbeans.modules.debugger.debug; import sun.tools.debug.*; import javax.swing.SwingUtilities; import javax.swing.JOptionPane; import java.util.ResourceBundle; import org.openide.TopManager; import org.openide.NotifyDescriptor; import org.openide.debugger.Debugger; import org.openide.debugger.DebuggerException; import org.openide.debugger.DebuggerNotFoundException; import org.openide.text.Line; import org.openide.util.RequestProcessor; import org.netbeans.modules.debugger.support.AbstractDebugger; import org.netbeans.modules.debugger.support.CoreBreakpoint; import org.netbeans.modules.debugger.support.DebuggerSettings; import org.netbeans.modules.debugger.support.ActionTIPanel; import org.netbeans.modules.debugger.support.util.*; /** * Debugger callback class. * * @author Jan Jancura */ class ToolsCallback implements DebuggerCallback { private boolean printLn = false; private boolean internalErrorReported = false; private ToolsDebugger debugger; private boolean stopOnMainReached = false; /** * Create the new callback for given debugger instance. */ ToolsCallback (ToolsDebugger debugger) { this.debugger= debugger; } /** * Implementation of dprint event. */ public void printToConsole (final String text) { SwingUtilities.invokeLater (new Runnable () { public void run () { if (text.startsWith ("[Internal debug-agent exception")) { // NOI18N internalErrorReported = true; return; } if (internalErrorReported && (text.equals ("\r\n")||text.equals ("\n"))) { // NOI18N internalErrorReported = false; return; } internalErrorReported = false; debugger.print (text, debugger.STD_OUT); } // run () }); // invokeLater } /** * Implementation of breakpoint event. * Tests if on the current line is some breakpoint and calls CoreBreakpoint.Event.perform. * If not, writes message to output, calls TheThread.setCurrent (true) and * updates state of threads, breakpoints... */ public void breakpointEvent (final RemoteThread t) { RequestProcessor.postRequest (new Runnable () { public void run () { final ResourceBundle bundle = org.openide.util.NbBundle.getBundle (ToolsCallback.class); Object[] v = null; // unsafe questions first... try { v = (Object[]) new Protector ("ToolsCallback.breakpointEvent") { // NOI18N public Object protect () throws Exception { Object[] r = new Object [6]; RemoteStackFrame fr = t.getCurrentFrame (); r [0] = fr; r [1] = fr.getRemoteClass ().getName (); r [2] = new Integer (fr.getLineNumber ()); r [3] = fr.getMethodName (); r [4] = t.getName (); r [5] = new Integer (t.dumpStack ().length); return r; } }.throwAndWait (debugger.synchronizer, debugger.killer); } catch (Throwable e) { if (e instanceof ThreadDeath) throw (ThreadDeath)e; debugger.println (bundle.getString ("EXC_Debugger") + ": " + e, debugger.ERR_OUT); return; } // read answers final RemoteStackFrame fr = (RemoteStackFrame) v [0]; String className = (String) v [1]; final int line = ((Integer) v [2]).intValue (); String methodName = (String) v [3]; final int stackDepth = ((Integer) v [5]).intValue (); // get lastStackDepth & lastAction final int lastStackDepth; final int lastAction; final ToolsThread ttt = ((ToolsThreadGroup) debugger.getThreadGroupRoot ()).getThread (t); if (ttt != null) { lastStackDepth = ttt.getLastStackDepth (); lastAction = ttt.getLastAction (); } else { lastStackDepth = stackDepth + 1; if (!stopOnMainReached && debugger.stopOnMainFlag) lastAction = debugger.ACTION_TRACE_INTO; else lastAction = debugger.ACTION_START; stopOnMainReached = true; } // the folloving condition tests if a 'step action' has been finished just now // its PATCH => we can to ignore breakpoints in this case if (!( (lastAction == debugger.ACTION_TRACE_INTO) || ( (lastAction == debugger.ACTION_TRACE_OVER) && (stackDepth <= lastStackDepth) ) || ( (lastAction == debugger.ACTION_STEP_OUT) && (stackDepth < lastStackDepth) ) ) ) { // Last action is GO || somma TRACE is not finished right now // is it breakpoint?!? if (resolveAsBreakpoint ( t, fr, className, methodName, line, lastAction, stackDepth, lastStackDepth )) return; } // no breakpoint // test if Trace over or Step out has not been interrupted by breakpoint with suspend=false if ( ( (lastAction == debugger.ACTION_TRACE_OVER) && (lastStackDepth < stackDepth) ) || ( (lastAction == debugger.ACTION_STEP_OUT) && (stackDepth > 1) && (lastStackDepth <= stackDepth) ) ) { new Protector ("ToolsCallback.stepOut") { // NOI18N public Object protect () throws Exception { t.stepOut (); return null; } }.go (debugger.synchronizer, debugger.killer); return; } // not breakpoint -> stop debugger.setDebuggerState (debugger.DEBUGGER_STOPPED); final String all = className + "." + v [3]; // NOI18N final String threadName = (String) v [4]; SwingUtilities.invokeLater (new Runnable () { public void run () { // show message if (debugger.isFollowedByEditor ()) { Line l = debugger.getLine (fr); if (l != null) { if (resolveCanBeCurrent ( t, false, l )) return; debugger.println ( bundle.getString ("CTL_Thread") + " " + threadName + " " + bundle.getString ("CTL_stopped_at") + " " + all + " " + bundle.getString ("CTL_line") + " " + line + ".", debugger.ERR_OUT + debugger.STL_OUT ); } else { DebuggerSettings debuggerSettings = (DebuggerSettings) DebuggerSettings. findObject (DebuggerSettings.class); if (!debuggerSettings.isActionOnTraceIntoSet ()) { // ask user, what to do ... ActionTIPanel ap = new ActionTIPanel (); NotifyDescriptor.Confirmation mess = new NotifyDescriptor.Confirmation ( ap, NotifyDescriptor.OK_CANCEL_OPTION ); Object o = TopManager.getDefault ().notify (mess); if (o.equals (NotifyDescriptor.OK_OPTION)) ap.updateSettings (); } if (debuggerSettings.getActionOnTraceInto () != DebuggerSettings.ACTION_ON_TI_STOP ) { try { debugger.stepOut (); } catch (DebuggerException e) { } return; } debugger.println ( bundle.getString ("CTL_Thread") + " " + threadName + " " + bundle.getString ("CTL_stopped_at") + " " + all + " " + bundle.getString ("CTL_line") + " " + line + " - " + bundle.getString ("CTL_unavailable_source_file") + ".", debugger.ERR_OUT + debugger.STL_OUT ); } } else debugger.println ( bundle.getString ("CTL_Thread") + " " + threadName + " " + bundle.getString ("CTL_stopped_at") + " " + all + " " + bundle.getString ("CTL_line") + " " + line + ".", debugger.ERR_OUT + debugger.STL_OUT ); // refresh all try { debugger.threadGroup.threadChanged (); } catch (Error e) { if (e instanceof ThreadDeath) throw (ThreadDeath)e; debugger.println (bundle.getString ("EXC_Debugger") + ": " + e, debugger.ERR_OUT); return; } ToolsThread tt = ((ToolsThreadGroup) debugger.getThreadGroupRoot ()).getThread (t); if (tt != null) tt.setCurrent (true); else debugger.lastCurrentThread = t; debugger.updateWatches (); } }); } }, 200); } /** * Implementation of exception event. */ public void exceptionEvent (final RemoteThread t, final String errorText) { RequestProcessor.postRequest (new Runnable () { public void run () { final ResourceBundle bundle = org.openide.util.NbBundle.getBundle (ToolsCallback.class); Object[] v = null; // unsafe questions first... try { v = (Object[]) new Protector ("ToolsCallback.exceptionEvent") { // NOI18N public Object protect () throws Exception { Object[] r = new Object [6]; RemoteStackFrame fr = t.getCurrentFrame (); r [0] = fr; r [1] = fr.getRemoteClass ().getName (); r [2] = new Integer (fr.getLineNumber ()); r [3] = fr.getMethodName (); r [4] = t.getName (); r [5] = new Integer (t.dumpStack ().length); return r; } }.throwAndWait (debugger.synchronizer, debugger.killer); } catch (Throwable e) { if (e instanceof ThreadDeath) throw (ThreadDeath)e; debugger.println (bundle.getString ("EXC_Debugger") + ": " + e, debugger.ERR_OUT); return; } // read answers final RemoteStackFrame fr = (RemoteStackFrame) v [0]; String className = (String) v [1]; final int line = ((Integer) v [2]).intValue (); final String all = className + "." + v [3]; // NOI18N final String threadName = (String) v [4]; final int stackDepth = ((Integer) v [5]).intValue (); final int lastStackDepth; final int lastAction; final ToolsThread ttt = ((ToolsThreadGroup) debugger.getThreadGroupRoot ()).getThread (t); if (ttt != null) { lastStackDepth = ttt.getLastStackDepth (); lastAction = ttt.getLastAction (); } else { lastStackDepth = stackDepth + 1; lastAction = debugger.getLastAction (); } // is there a breakpoint setted on thrown exception ? final String exClassName = Utils.getExceptionName (errorText); if (exClassName != null) { try { AbstractDebugger deb = (AbstractDebugger) TopManager.getDefault ().getDebugger (); CoreBreakpoint [] b = deb.findBreakpoints (exClassName); ExceptionBreakpoint br = null; CoreBreakpoint.Event ev; int i, k = b.length; for (i = 0; i < k; i++) { ev = b[i].getEvent (debugger); if (ev instanceof ExceptionBreakpoint) { br = (ExceptionBreakpoint) ev; break; } } if (br!=null) { br.exceptionName = exClassName; br.perform (t); return; } } catch (DebuggerNotFoundException e) {} } // breakpoint not found, default handling will be performed debugger.setDebuggerState (debugger.DEBUGGER_STOPPED); SwingUtilities.invokeLater (new Runnable () { public void run () { // show message String mes = new String (bundle.getString ("CTL_An_exception") + " " + bundle.getString ("CTL_reached_at") + " " + all + " " + bundle.getString ("CTL_line") + " " + line); debugger.print (mes + ". " + errorText, debugger.ERR_OUT); // NOI18N if (debugger.isFollowedByEditor ()) { Line l = debugger.getLine (fr); if (l != null) { debugger.println (mes + ".", debugger.STL_OUT); // NOI18N } else { debugger.println (mes + " - " + bundle.getString ("CTL_unavailable_source_file") + ".", debugger.STL_OUT); } } else debugger.println (mes + ".", debugger.STL_OUT); // NOI18N // refresh all try { debugger.threadGroup.threadChanged (); } catch (Error e) { if (e instanceof ThreadDeath) throw (ThreadDeath)e; debugger.println (bundle.getString ("EXC_Debugger") + ": " + e, debugger.ERR_OUT); return; } final ToolsThread tt = ((ToolsThreadGroup) debugger.getThreadGroupRoot ()).getThread (t); if (tt != null) tt.setCurrent (true); else debugger.lastCurrentThread = t; debugger.updateWatches (); } }); } }, 200); } /** * Implementation of thread death event. */ public void threadDeathEvent (final RemoteThread t) { SwingUtilities.invokeLater (new Runnable () { public void run () { try { ResourceBundle bundle = org.openide.util.NbBundle.getBundle (ToolsCallback.class); debugger.println ( bundle.getString ("CTL_Thread_death_event") + ": " + t.getName (), debugger.ERR_OUT ); } catch (Throwable e) { if (e instanceof ThreadDeath) throw (ThreadDeath)e; } } // run () }); // invokeLater } /** * Implementation of debugger finish event. */ public void quitEvent () { SwingUtilities.invokeLater (new Runnable () { public void run () { try { ResourceBundle bundle = org.openide.util.NbBundle.getBundle (ToolsCallback.class); debugger.println (bundle.getString ("CTL_Process_death_event"), debugger.ERR_OUT); debugger.finishDebugger (); } catch (Throwable e) { if (e instanceof ThreadDeath) throw (ThreadDeath)e; } } // run () }); // invokeLater } // helper methods ............................................................ /** * Tries to resolve as breakpoint. * * @return true if resolved (is on breakpoint or can not mark * this line current). */ private boolean resolveAsBreakpoint ( RemoteThread t, RemoteStackFrame fr, String className, String methodName, int line, int lastAction, int stackDepth, int lastStackDepth ) { try { AbstractDebugger deb = (AbstractDebugger) TopManager.getDefault (). getDebugger (); CoreBreakpoint b = deb.findBreakpoint (className, line); if (b != null) { CoreBreakpoint.Event ev = b.getEvent (debugger); if (ev instanceof LineBreakpoint) { Line l = debugger.getLine (fr); if (resolveCanBeCurrent ( t, true, l )) return true; ((LineBreakpoint) ev).perform (t); return true; } } if ( (lastAction != debugger.ACTION_TRACE_OVER) || (lastStackDepth != stackDepth) ) { b = deb.findBreakpoint (className, methodName); if (b != null) { CoreBreakpoint.Event ev = b.getEvent (debugger); if (ev instanceof MethodBreakpoint) { Line l = debugger.getLine (fr); if (resolveCanBeCurrent ( t, true, l )) return true; ((MethodBreakpoint) ev).perform (t); return true; } } } } catch (DebuggerNotFoundException e) { } return false; } /** * Asks Line if it can be current. If it can not => stepOver. * * @returns true if is is resolved => if it can not be current * => stepOver. */ private boolean resolveCanBeCurrent ( final RemoteThread t, boolean isBreakpoint, Line l ) { if (l == null) return false; if (!debugger.canBeCurrent (l, false)) { // this line cannot be marked as current (non-java // languages support) new Protector ("ToolsCallback.next") { // NOI18N public Object protect () throws Exception { t.next (); return null; } }.go (debugger.synchronizer, debugger.killer); return true; } return false; } } /* * Log * 20 Gandalf-post-FCS1.18.4.0 3/28/00 Daniel Prusa * 19 Gandalf 1.18 1/18/00 Jan Jancura More buttons... * 18 Gandalf 1.17 1/18/00 Jan Jancura Dialog for action on TI * settings. * 17 Gandalf 1.16 1/17/00 Jan Jancura Some propertie removed * form DebugerSettings * 16 Gandalf 1.15 1/13/00 Daniel Prusa NOI18N * 15 Gandalf 1.14 1/11/00 Daniel Prusa bugfix for #5256 + * additional filtering of [Internal debug-agent exception] message * 14 Gandalf 1.13 12/9/99 Daniel Prusa ExceptionBreakpoint * 13 Gandalf 1.12 12/7/99 Daniel Prusa added handling of * breakpoint on method event * 12 Gandalf 1.11 11/29/99 Jan Jancura Bug 3341 - bad \n in * output of debugger Bug 3372 - do not print internal debugger * messages... * 11 Gandalf 1.10 11/8/99 Jan Jancura Somma classes renamed * 10 Gandalf 1.9 10/23/99 Ian Formanek NO SEMANTIC CHANGE - Sun * Microsystems Copyright in File Comment * 9 Gandalf 1.8 10/1/99 Jan Jancura Current thread & bug 4108 * 8 Gandalf 1.7 7/30/99 Jan Jancura * 7 Gandalf 1.6 7/24/99 Jan Jancura Bug in Suspend / resume * thread in enterprise deb. * 6 Gandalf 1.5 6/9/99 Jan Jancura * 5 Gandalf 1.4 6/9/99 Ian Formanek ---- Package Change To * org.openide ---- * 4 Gandalf 1.3 6/4/99 Jan Jancura * 3 Gandalf 1.2 6/4/99 Jan Jancura * 2 Gandalf 1.1 6/4/99 Jan Jancura * 1 Gandalf 1.0 6/1/99 Jan Jancura * $ */